package ubadbtools.deadlockAnalyzer.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import ubadbtools.deadlockAnalyzer.DeadlockValidation;
import ubadbtools.deadlockAnalyzer.ScheduleValidation;
import ubadbtools.deadlockAnalyzer.scheduleRecords.ScheduleRecord;
import ubadbtools.deadlockAnalyzer.results.ValidationResult;

public class Schedule
{
	//[start] Atributos
	private List<ScheduleRecord> scheduleRecords;
	private Set<String> items;	//Uso sets para evitar repetidos
	private Set<String> transactions;
	private DeadlockModelType deadlockModelType;
	private int globalTimestamp;
	private Map<String, Integer> timeStampByTransaction;
	//[end]
	
	//[start] Constructor
	public Schedule(DeadlockModelType type)
	{
		scheduleRecords 	= new ArrayList<ScheduleRecord>();
		items 				= new LinkedHashSet<String>();	//Uso esta clase porque me provee un orden de iteraci�n predecible (no como HashSet)
		transactions		= new LinkedHashSet<String>();
		deadlockModelType	= type;
		globalTimestamp		= 0;
		timeStampByTransaction = new HashMap<String,Integer>();
	}
	//[end]

	//[start] Getters
	public List<ScheduleRecord> getScheduleRecords()
	{
		return scheduleRecords;
	}
	
	public Set<String> getItems()
	{
		return items;
	}

	public Set<String> getTransactions()
	{
		return transactions;
	}
	
	public DeadlockModelType getDeadlockModelType()
	{
		return deadlockModelType;
	}
	
	public Map<String, Integer> getTimestamps()
	{
		return timeStampByTransaction;
	}
	//[end]
	
	//[start] Add
	public void addRecord(ScheduleRecord record)
	{
		if(record.isStart())
		{
			//Se agrego un start al schedule, comienza una transaccion-> le asigno un timestamp
			timeStampByTransaction.put(record.getTransaction(),globalTimestamp);
			record.setTimestamp(globalTimestamp);
			globalTimestamp++;
		}
		else
		{
			if(timeStampByTransaction.containsKey(record.getTransaction()))
				record.setTimestamp(timeStampByTransaction.get(record.getTransaction()));
			else
				record.setTimestamp(-1);
		}
		
		scheduleRecords.add(record);
	}
	
	public void addItem(String item)
	{
		items.add(item);
	}

	public void addTransaction(String transaction)
	{
		transactions.add(transaction);
	}
	//[end]

	//[start] replace
	public void replaceRecord(int position, ScheduleRecord record)
	{
		scheduleRecords.set(position, record);
	}
	//[end]
	
	//[start] Validate
	public ValidationResult validate()
	{
		return ScheduleValidation.executeFor(this);
	}
	//[end]
	
	//[start] ValidateDeadlock
	public ValidationResult preventDeadlock(ScheduleRecord record)
	{
		return DeadlockValidation.executeFor(this,record);
	}
	
	public ValidationResult preventDeadlock()
	{
		return DeadlockValidation.executeFor(this);
	}
	//[end]
	
	public void fillTimestamps()
	{
		globalTimestamp = 0;
		int timestampTemporal = 0;
		
		for(ScheduleRecord rec : getScheduleRecords())
		{
			timestampTemporal = rec.getTimestamp();
			timeStampByTransaction.put(rec.getTransaction(), timestampTemporal);
			globalTimestamp = (globalTimestamp < timestampTemporal) ? timestampTemporal : globalTimestamp;
		}
		globalTimestamp++;
	}
}
